home *** CD-ROM | disk | FTP | other *** search
- ; REMINDER.ASM
- ; Resident clock pop-up utility with hourly bell and appointment chime.
-
- ; REMINDER [foreground color],[border color],[scan code of hot key],
- ; [hourly tone frequency],[alarm tone frequency]
-
- CODE SEGMENT ;*************************
- ASSUME CS:CODE,DS:CODE ;* *
- ORG 100H ;* REMEMBER TO EXE2BIN *
- ;* *
- START: JMP INITIALIZE ;*************************
-
- ; DATA AREA
- ; ---------
- COPYRIGHT DB 'Copyright 1987 Ziff-Davis Publishing Co.',1AH
- PROGRAMMER DB 'Michael J. Mefford'
-
- OLD_TIMER DD ?
- OLD_KEYBOARD DD ?
- OLD_CURSPOS DW ?
- CURSOR_TYPE DW ?
- CURSPOS DW 325H
- STATUS_REG DW ?
- SCREEN_SEG DW 0B000H
- TIMER_HIGH DW ?
- LAST_HOUR DW ?
- BELL_COUNT DB 0
- HERTZ DW ?
-
- BUSY DB 0
- DISPLAY_FLAG DB 1
- ALARM_FLAG DB 1
- MATCH_FLAG DB 0
- POPUP_FLAG DB 0
- VIDEO_FLAG DB 0
-
- FOREGROUND DW 07H
- BORDER DW 70H
- HOT_KEY DW 19
- HOURLY_FREQ DW 2217
- ALARM_FREQ DW 2960
-
- DISPATCH_KEY DB 59,60,61,62,71,72,75,77,79,80
- DISPATCH_TABLE DW OFFSET ERASE , OFFSET ALARM_ABLE
- DW OFFSET INSERT , OFFSET DISPLAY_ABLE
- DW OFFSET HOME_KEY , OFFSET CURS_UP
- DW OFFSET CURS_LEFT , OFFSET CURS_RIGHT
- DW OFFSET END_KEY , OFFSET CURS_DOWN
-
- SKIP DB 39,42,44,45,46
- DIS DB 'Dis'
- EN DB ' En'
- WEEKDAY DB 'SunMonTueWedThuFriSat'
-
-
- ;************* KEYBOARD INTERCEPTOR ************;
-
- ;-----------------------------------------------------------------;
- ; Let BIOS get the keystroke then see if we should pop up window. ;
- ;-----------------------------------------------------------------;
-
- NEW_KEYBOARD: STI ;Turn interrupts back on
- PUSHF ;Simulate an interrupt
- CALL CS:OLD_KEYBOARD ; by pushing flags and far call.
-
- PUSHF ;On return save all registers
- PUSH DS ; that will be used.
- PUSH ES
- PUSH AX
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH SI
- PUSH DI
- PUSH BP
-
- PUSH CS ;Point to our data.
- POP DS
- CLD ;Moves in forward direction.
- CMP BUSY,0 ;If the window is already popped
- JNZ DONE_HERE ; exit Int 9 back to window.
- CMP VIDEO_FLAG,1 ;If graphics mode, exit.
- JZ DONE_HERE
- CMP POPUP_FLAG,1 ;If event happened, pop up.
- JZ OPEN_WINDOW
- MOV AH,1 ;Is an ASCII character ready?
- INT 16H
- JZ DONE_HERE ;If it's just a key release, exit.
- CMP AL,0 ;Is it extended code?
- JNZ DONE_HERE ;If no, exit.
- CMP AH,BYTE PTR HOT_KEY ;Else, see if our key combo.
- JZ OPEN_WINDOW ;If yes, open window
- DONE_HERE: JMP EXIT_KEYBOARD ; else exit.
-
- ;------------------------------------------------------------------------;
- ; Save screen so we can pop up REMINDER. Save cursor position and mode. ;
- ;------------------------------------------------------------------------;
-
- OPEN_WINDOW: OR BUSY,1 ;Flag that window is open.
- XOR DISPLAY_FLAG,2 ;Enable time display.
- MOV AH,0 ;Retrieve and discard hot key
- INT 16H ; character from keyboard buffer.
- CALL STORE_SCREEN ;Store screen.
- XOR BH,BH
- MOV AH,3
- INT 10H ;Retrieve
- MOV OLD_CURSPOS,DX ; cursor mode and save.
- MOV CX,0B0CH ;Assume monocard underscore cursor
- CMP STATUS_REG,3BAH ;Confirm via status register.
- JZ MONO_CURSOR ;If yes, change cursor.
- MOV CX,0607H ;Else, assume color card cursor
- MONO_CURSOR: MOV CURSOR_TYPE,CX
- MOV AH,1 ; and set cursor type.
- INT 10H
-
- ;-------------------------------------------;
- ; This is the main loop. The keyboard will ;
- ; be monitored and appropriate subroutines ;
- ; will service the proper key responses. ;
- ;-------------------------------------------;
-
- ;***********;
- ; MAIN LOOP ;
- ;***********;
-
- READ_KEY: MOV SI,OFFSET WINDOW ;Update our window.
- CALL POP_UP
- CALL SET_CURSPOS ;Update cursor position.
- MOV AH,0 ;Wait for an ASCII character.
- INT 16H
- CMP AL,27 ;Is it Esc?
- JZ EXIT_WINDOW
- CMP AL,13 ;Is it carriage return?
- JNZ CK_BS
- CALL CR
- JMP SHORT READ_KEY
- CK_BS: CMP AL,8 ;Is it backspace?
- JNZ CK_ASCII
- CALL BS
- JMP SHORT READ_KEY
- CK_ASCII: CMP AL,0 ;Is it an extended scan code?
- JNZ ASCII ;If no, it's ASCII
-
- CMP AH,BYTE PTR HOT_KEY ;Is it our key combo?
- JZ EXIT_WINDOW ;If yes, exit window.
- MOV CX,10 ;Check for a match with
- MOV DI,OFFSET DISPATCH_KEY ; one of the twelve extended
- XCHG AH,AL ; codes from our dispatch table.
- REPNZ SCASB
- JNZ READ_KEY ;If no match, next key.
- MOV DI,OFFSET DISPATCH_TABLE+18 ;point to end of offsets.
- SHL CX,1 ;Double count.
- SUB DI,CX ;Subtract to get offset.
- CALL DS:[DI] ;Call the subroutine.
- JMP SHORT READ_KEY ;Then return for next key.
-
- ASCII: MOV BX,CURSPOS ;Retrieve cursor position.
- CMP BL,78 ;Is it in last column?
- JZ READ_KEY ;If yes, skip.
- CMP AL,32 ;Is it space?
- JZ STORE_ASCII ;If yes, store.
- JB READ_KEY ;If below, skip.
- CMP BL,43 ;Is it AM/PM column?
- JNZ STORE_ASCII ;If no, store.
- AND AL,5FH ;Else, capitalize.
- CMP AL,'A' ;Check to see if A or P.
- JZ STORE_ASCII
- CMP AL,'P'
- JNZ READ_KEY
- STORE_ASCII: CALL STORE_CHAR
- MOV BX,1 ;Increment cursor position.
- CALL MOVE_CURSOR
-
- JMP SHORT READ_KEY
-
- ;***************;
- ; END MAIN LOOP ;
- ;***************;
-
- ;------------------------------------;
- ; This is the keyboard exit routine. ;
- ;------------------------------------;
-
- EXIT_WINDOW: XOR DISPLAY_FLAG,2 ;Restore the time display state.
- MOV SI,OFFSET SCREEN ;Point to the stored screen
- CALL POP_UP ; and restore the screen.
- MOV DX,OLD_CURSPOS ;Retrieve old cursor postion
- CALL ROW_COLUMN ; and restore.
- MOV CX,CURSOR_TYPE ;Retrieve old cursor type
- MOV AH,1 ; and restore.
- INT 10H
- AND POPUP_FLAG,0 ;Restore pop up flag.
- AND BUSY,0 ;Flag done with window.
-
- EXIT_KEYBOARD: POP BP ;Restore all registers.
- POP DI
- POP SI
- POP DX
- POP CX
- POP BX
- POP AX
- POP ES
- POP DS
- POPF
- IRET ;Return from interrupt.
-
- ;--------------------------------------;
- ; This subroutine retrieves and stores ;
- ; the upper right corner of screen. ;
- ;--------------------------------------;
-
- STORE_SCREEN: MOV DX,STATUS_REG ;Retrieve the status register.
- MOV AX,SCREEN_SEG ;Point to screen segment.
- MOV DS,AX
- PUSH CS
- POP ES
- MOV SI,70 ;Point to start of window.
- MOV DI,OFFSET SCREEN ;Point to storage.
- MOV BX,17 ;17 rows to save.
-
- READ_SCREEN: MOV CX,45 ;45 characters per row.
- HORZ_RET1: IN AL,DX ;Get status.
- TEST AL,1 ;Is it low?
- JNZ HORZ_RET1 ;If no, wait until it is.
- CLI ;No more interrupts.
-
- WAIT1: IN AL,DX ;Get status
- TEST AL,1 ;Is it high?
- JZ WAIT1 ;If no, wait until it is.
- LODSW ;Retrieve a word.
- STI ;Interrupts back on.
- STOSW ;Store the character/attribute.
- LOOP HORZ_RET1 ;Get next byte.
- ADD SI,70 ;Point to next row
- DEC BX
- JNZ READ_SCREEN
- PUSH CS ;Restore data segment.
- POP DS
- RET ;Return.
-
- ;-------------------------------------------------;
- ; This subroutine controls the position we write ;
- ; to the screen and the number of rows we write. ;
- ;-------------------------------------------------;
-
- POP_UP: MOV DI,70 ;Starting column 70/2 = 35
- MOV BP,17 ;17 rows to write.
- NEXT_ROW1: MOV CX,45 ;45 characters per row.
- CALL WRITE_SCREEN
- ADD DI,70 ;Increment to next row.
- DEC BP
- JNZ NEXT_ROW1
- RET
-
- ;---------------------------------------------;
- ; This subroutine writes to the screen buffer ;
- ;---------------------------------------------;
-
- WRITE_SCREEN: MOV DX,STATUS_REG ;Retrieve status register
- MOV AX,SCREEN_SEG ;Point to the screen buffer.
- MOV ES,AX
-
- PUT_BYTE: LODSW ;Get a byte.
- MOV BX,AX ;Store it in AX.
-
- HORZ_RET2: IN AL,DX ;Get status.
- TEST AL,1 ;Is it low?
- JNZ HORZ_RET2 ;If no, wait until it is.
- CLI ;No more interrupts.
-
- WAIT2: IN AL,DX ;Get status.
- TEST AL,1 ;Is it high?
- JZ WAIT2 ;If no, wait until it is.
- MOV AX,BX ;Retrieve the word
- STOSW ; and store it.
- STI ;Interrupts back on.
- LOOP PUT_BYTE ;Write next character/attribute.
- PUSH CS
- POP ES
- RET
-
- ;-----------------------------------------------------;
- ; This subroutine stores what is typed in the window. ;
- ;-----------------------------------------------------;
-
- STORE_CHAR: MOV BX,CURSPOS ;Retrieve cursor position.
- MOV CL,AL ;Save character.
- MOV AX,90 ;90 characters per row.
- MUL BH ;Times cursor row.
- SUB BL,35 ;Adjust column.
- SHL BL,1 ;Double for attributes.
- XOR BH,BH
- ADD BX,AX ;Add column/row for offset.
- ADD BX,OFFSET WINDOW ;Add window offset.
- MOV [BX],CL ;Store the character.
- RET
-
- ;-----------------------------------------------------;
- ; These subroutines move and set the cursor position. ;
- ;-----------------------------------------------------;
-
- MOVE_CURSOR: MOV AX,CURSPOS ;Retrieve current position.
- ADD AH,BH ;Add requested row move.
- NEXT_MOVE: ADD AL,BL ;Add requested column move.
- MOV CX,5 ;Check restricted columns.
- MOV DI,OFFSET SKIP ;Point to table.
- REPNZ SCASB
- JZ NEXT_MOVE ;If off limits move another.
- MOV CURSPOS,AX ;Store new position.
- CALL SET_CURSPOS ;Move cursor.
- RET
-
- SET_CURSPOS: MOV DX,CURSPOS
- ROW_COLUMN: XOR BH,BH ;Page zero.
- MOV AH,2 ;Move cursor via BIOS.
- INT 10H
- RET
-
- ;------------------------------------------------------;
- ; These subroutines control the movement of the cursor ;
- ;------------------------------------------------------;
-
- CURS_RIGHT: MOV BX,1 ;Plus one column to move.
- CMP DL,78 ;Already far right column?
- JNZ END_CURSOR ;If no, move it.
- RET
-
- CURS_LEFT: MOV BX,0FFH ;Minus one column to move.
- CMP DL,37 ;Already far left column?
- JNZ END_CURSOR ;If no, move it.
- RET
-
- CURS_UP: MOV BX,0FF00H ;Minus one row to move.
- CMP DH,3 ;Is it already top?
- JNZ END_CURSOR ;If no, move it.
- RET
-
- CURS_DOWN: MOV BX,100H ;Plus one row to move.
- CMP DH,12 ;Is it already bottom?
- JNZ END_CURSOR ;If no, move it.
- RET
-
- BS: CMP DL,37 ;Is it already far left?
- JZ BS_RETURN ;If yes, skip.
- MOV BX,0FFH ;Else, minus one column to move.
- CALL MOVE_CURSOR ;Move it.
- MOV AL,32 ;Store space in that position.
- CALL STORE_CHAR
- BS_RETURN: RET
-
- CR: MOV BYTE PTR CURSPOS,37 ;Move cursor to first column.
- MOV BX,100H ;Plus one row to move.
- CMP DH,12 ;Already at bottom?
- JNZ END_CURSOR ;If no, move it.
- MOV BX,0 ;Else, zero row move.
-
- END_CURSOR: CALL MOVE_CURSOR
- RET
-
- ;---------------------------------------------------;
-
- HOME_KEY: MOV BYTE PTR CURSPOS,37 ;Move to first column.
- JMP SHORT END_POSITION
-
- END_KEY: MOV BYTE PTR CURSPOS,78 ;Move to last column.
- END_POSITION: CALL SET_CURSPOS
- RET
-
- ;---------------------------------------------------;
- ; These subroutines delete a line or insert a line. ;
- ;---------------------------------------------------;
-
- ERASE: CALL GET_COUNT ;Prepare for moving lines.
- JZ BLANK_LINE ;Skip if zero lines to move.
- MOV SI,DI
- ADD SI,90
- REP MOVSB ;Else, move the lines up
- JMP SHORT BLANK_LINE ;Blank out bottom line.
-
- INSERT: CALL GET_COUNT ;Prepare for moving lines.
- JZ BLANK_LINE ;Skip if zero lines to move.
- MOV SI,OFFSET WINDOW+90*12-2
- MOV DI,OFFSET WINDOW+90*13-2
- STD
- REP MOVSB ;Else, move the lines down.
- CLD
- SUB DI,88 ;Adjust pointer.
-
- BLANK_LINE: MOV AL,32 ;Blank the line with space
- MOV AH,BYTE PTR FOREGROUND ;and foreground color.
- INC DI
- INC DI
- MOV CX,43 ;43 characters.
- REP STOSW
- MOV BYTE PTR DS:[DI-80],':' ;Restore the delimiter
- MOV BYTE PTR DS:[DI-70],'M' ; characters
- MOV BYTE PTR CURSPOS,37 ; and move the cursor.
- RET
-
- GET_COUNT: MOV CX,90*12 ;Assume last row.
- MOV DL,BYTE PTR CURSPOS+1 ;Retrieve cursor row.
- MOV AX,90 ;Times 90 characters per row.
- MUL DL
- MOV DI,OFFSET WINDOW ;Point to start of window entries
- ADD DI,AX ;Add offset of row and subtract
- SUB CX,AX ; to get characters to move.
- RET
-
- ;--------------------------------------------------------------;
- ; These subroutines toggle either the alarm or display status. ;
- ;--------------------------------------------------------------;
-
- ALARM_ABLE: MOV AX,TIMER_HIGH ;Update last hour so hourly
- MOV LAST_HOUR,AX ; alarm will not go off
- MOV DI,OFFSET WINDOW+(14*90)+70 ; if toggled on.
- XOR ALARM_FLAG,1 ;Toggle alarm flag.
- CMP ALARM_FLAG,0 ;Set carry flag to indicate
- JMP SHORT SHOW_ABLE ; status and display.
-
- DISPLAY_ABLE: XOR DISPLAY_FLAG,1 ;Toggle display flag
- CMP DISPLAY_FLAG,2 ;Set carry flag.
- JNZ SHOW_TIME
- MOV AH,SCREEN+47 ;Use the attribute next door
- MOV AL,32 ; with space to clear time
- MOV DI,OFFSET SCREEN+48 ; from screen data.
- MOV CX,21
- REP STOSW
- SHOW_TIME: MOV DI,OFFSET WINDOW+(15*90)+70
- CMP DISPLAY_FLAG,2
-
- SHOW_ABLE: MOV SI,OFFSET DIS ;If flag zero
- JZ SHOW_THIS ; show "Disable"
- MOV SI,OFFSET EN ; else show "Enable"
-
- SHOW_THIS: MOV CX,3 ;Move the three bytes
- SHOW_STORE: MOVSB ; into the window.
- INC DI ;Bump past attribute.
- LOOP SHOW_STORE
- RET
-
- ;************* TIMER INTERCEPTOR *************;
-
- NEW_TIMER: STI ;Interrupts back on
- PUSHF ; and save all registers
- PUSH DS ; that we will use.
- PUSH ES
- PUSH AX
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH SI
- PUSH DI
-
- ;-----------------------------------;
- ; Retrieve the video mode and time. ;
- ;-----------------------------------;
-
- CLD ;String moves in forward direction
- PUSH CS ;Point to our data.
- POP DS
- MOV AX,40H ;Point to BIOS data.
- MOV ES,AX
- MOV AL,ES:[49H] ;Retrieve video mode.
- MOV CL,0 ;Assume text mode.
- CMP AL,2 ;Is it graphics or 40 column?
- JZ STORE_MODE ;If no, flag as OK.
- CMP AL,3
- JZ STORE_MODE
- CMP AL,7
- JZ STORE_MODE
- MOV CL,1 ;Else, flag as not OK.
- STORE_MODE: MOV VIDEO_FLAG,CL
- MOV CX,ES:[6CH] ;Retrieve timer low
- MOV AX,ES:[6EH] ; and timer high.
- MOV TIMER_HIGH,AX
- PUSH CS ;Restore extra segment.
- POP ES
-
- ;---------------------------------------;
- ; Convert the timer to 12 hour meridian ;
- ; format and store in the window. ;
- ;---------------------------------------;
-
- MOV BL,'A' ;Assume AM
- CMP AX,24 ;If midnight display AM
- JE DISPLAY_MUNDI
- CMP AX,11 ;If before noon display AM
- JBE DISPLAY_MUNDI
- MOV BL,'P' ;Else, display PM.
- DISPLAY_MUNDI: MOV DI,OFFSET WINDOW+86
- CMP AX,12 ;Adjust if over 12.
- JBE DISPLAY_HOUR
- SUB AX,12
- DISPLAY_HOUR: MOV [DI],BL ;Store either the "A" or "P".
- SUB DI,12 ;Point to hour.
- MOV BH,1 ;Supress leading zero.
- CALL STORE_NUMBER ;Store hour.
-
- MOV AX,CX ;Retrieve timer low.
- XOR DX,DX
- MOV CX,1093 ;And divide by 1093 counts
- DIV CX ; per minute.
- MOV BH,0 ;Don't suppress leading zero.
- MOV CL,WINDOW+82 ;Retrieve current minute.
- CALL STORE_NUMBER ;Store new minute.
- CMP AL,CL ;Check if one minute has gone by.
- JZ TIME_DONE ;If no, skip.
- MOV MATCH_FLAG,0 ;If yes, reset match flag.
-
- ;---------------------------------------------------;
- ; Display time unless disabled or in graphics mode. ;
- ;---------------------------------------------------;
-
- TIME_DONE: CMP DISPLAY_FLAG,0 ;Skip display if display flag low
- JZ CK_MATCH
- CMP VIDEO_FLAG,1 ;Skip also if in graphics mode.
- JZ CK_MATCH
-
- DISPLAY_TIME: MOV SI,OFFSET WINDOW+48 ;Point to date and time.
- MOV DI,2*59 ;Point to top left of screen.
- MOV CX,21 ;Display the 21 characters of
- CALL WRITE_SCREEN ; date and time.
-
- ;----------------------------------------;
- ; Compare the current date and time with ;
- ; alarm date and time fields in window. ;
- ;----------------------------------------;
-
- CK_MATCH: CMP MATCH_FLAG,2
- JZ GOT_MATCH
- MOV AX,10 ;Check the 10 possible time
- MOV BX,OFFSET WINDOW+274 ; entry fields of time with
- COMP_TIME: MOV DI,OFFSET WINDOW+74 ; the current time.
- MOV SI,BX
- MOV CX,7 ;There are 7 bytes in time field.
- REPZ CMPSW
- JZ MATCH ;If match, alarm.
- ADD BX,90
- DEC AX
- JNZ COMP_TIME
-
- ;-------------------------------------;
- ; If we didn't get a match with event ;
- ; alarm, see if the hour has changed. ;
- ;-------------------------------------;
-
- HOURLY_ALARM: CMP ALARM_FLAG,0 ;Skip if hourly alarm is disabled
- JZ EXIT_TIMER
- MOV AX,TIMER_HIGH ;Else, see if hour has changed
- CMP AX,LAST_HOUR
- JZ EXIT_TIMER ;If no, exit
- MOV BX,HOURLY_FREQ ;Else, ring hourly alarm.
- CALL BELL
- JMP SHORT EXIT_TIMER ;And exit.
-
- ;-----------------------------------------;
- ; If we have a match, ring message alarm. ;
- ;-----------------------------------------;
-
- MATCH: CMP MATCH_FLAG,0 ;Is the message alarm done?
- JNZ EXIT_TIMER ;If yes, exit
- NEG AX ;Else, subtract match count
- ADD AX,13 ; from 13 to get cursor row.
- XCHG AH,AL
- MOV AL,37 ;First column.
- MOV CURSPOS,AX ;Point to matching event.
- MOV POPUP_FLAG,1 ;Flag so will pop up when able.
- MOV MATCH_FLAG,2
- GOT_MATCH: MOV BX,ALARM_FREQ ;Ring event alarm.
- CALL BELL
-
- EXIT_TIMER: POP DI ;Restore registers
- POP SI
- POP DX
- POP CX
- POP BX
- POP AX
- POP ES
- POP DS
- POPF
-
- JMP CS:OLD_TIMER ;And service old timer interrupt.
-
- ;--------------------------------------------------------------;
- ; This subroutine turns the speaker on and off for the alarms. ;
- ;--------------------------------------------------------------;
-
- BELL: CMP BELL_COUNT,14*2 ;Toggle the speaker on and off
- JNZ START_BELL ; 14 times.
- IN AL,61H ;Get timer port
- AND AL,11111100B ; and mask off speaker bits.
- OUT 61H,AL
- MOV BELL_COUNT,0 ;Reset bell counter.
- MOV AX,TIMER_HIGH ;Update hour flag.
- MOV LAST_HOUR,AX
- MOV MATCH_FLAG,1 ;Turn off match flag for one min.
- RET ;Return.
-
- START_BELL: CMP BELL_COUNT,0 ;Is this first time through?
- JNZ TOGGLE_BELL ;If yes, toggle the bell
- MOV AL,10110110B ;Else, initialize the 8253.
- OUT 43H,AL
- MOV DX,12H ;Divide 120000H by divisor.
- XOR AX,AX
- DIV BX
- OUT 42H,AL ;Send divisor to chip.
- MOV AL,AH
- OUT 42H,AL
- IN AL,61H
- AND AL,11111100B ;Mask off speaker bits.
- OUT 61H,AL
-
-
- TOGGLE_BELL: IN AL,61H ;Get port 61h
- XOR AL,00000011B ;Toggle speaker.
- OUT 61H,AL
-
- INC BELL_COUNT ;Increment bell count.
- RET
-
- ;------------------------------------------------;
- ; This subroutine converts the number to decimal ;
- ; ASCII. Leading zero suppression is checked. ;
- ;------------------------------------------------;
-
- STORE_NUMBER: MOV BL,10 ;Divide by ten.
- DIV BL
- ADD AX,'00' ;Convert to ASCII.
- CMP BH,0 ;Suppress leading zero?
- JZ STORE_IT ;If no, store it.
- CMP AL,'0' ;Else, is it leading zero?
- JNZ STORE_IT ;If no, store it.
- MOV AL,32 ;Else store a space character.
- STORE_IT: STOSB
- XCHG AH,AL ;Retrieve the remainder.
- INC DI ;Bump past attribute.
- STOSB ;Store it.
- ADD DI,3 ;Point to next position.
- RET
-
- ;----------------------------------------------------------------------;
- ; This is the end of the resident code. Everything below is not needed ;
- ; after initialization so we will use the space for window storage. ;
- ;----------------------------------------------------------------------;
-
- SCREEN LABEL BYTE
- WINDOW EQU SCREEN+45*2*17
- END_RESIDENT EQU WINDOW+45*2*17
-
- ;************* INITIALIZATION *************;
-
- ;-------------------------------;
- ; Get the parameters and store. ;
- ;-------------------------------;
-
- INITIALIZE: CLD
- CMP BYTE PTR DS:[80H],0 ;Any parameters?
- JZ SETUP_WINDOW ;If no, skip.
- MOV SI,82H ;Else, point to parameters.
- MOV DI,OFFSET FOREGROUND ;Point to variables.
- MOV CX,5 ;Five variables.
- NEXT_PARSE: CMP BYTE PTR [SI-1],13 ;Carriage return?
- JZ SETUP_WINDOW ;If yes, done here.
- CMP BYTE PTR [SI],',' ;Delimiter?
- JNZ GET_IT ;If no, get parameter.
- INC SI ;Else, bump past comma.
- JMP SHORT NEXT_PARA ;Get next parameter.
- GET_IT: CALL GET_PARA
- MOV DS:[DI],BX ;Store parameter in variable.
- NEXT_PARA: INC DI ;Point to next variable.
- INC DI
- LOOP NEXT_PARSE
-
- ;---------------------------------------------------------------;
- ; To keep the program to its smallest possible size, the window ;
- ; has been conpressed. This routine uncompresses the data. ;
- ;---------------------------------------------------------------;
-
- SETUP_WINDOW: MOV AL,32 ;Fill window with space
- MOV AH,BYTE PTR BORDER ; and border color.
- MOV BX,OFFSET WINDOW
- MOV DI,BX
- MOV CX,45*17 ;45 columns X 17 rows.
- REP STOSW
-
- MOV AL,205 ;Double line character.
- MOV DI,OFFSET WINDOW+90+2 ;Top line.
- CALL STORE_LINE
-
- MOV DI,OFFSET WINDOW+(90*13)+2 ;Middle line.
- CALL STORE_LINE
-
- MOV DI,OFFSET WINDOW+(90*16)+2 ;Bottom line.
- CALL STORE_LINE
-
- MOV SI,OFFSET TEXT ;Point to text.
- MOV CX,5 ;Placement of 5 text strings.
- STORE_TEXT: LODSW ;Get offset.
- MOV DI,AX
- ADD DI,BX ;Add window offset.
- NEXT_TEXT: LODSB ;Get character.
- CMP AL,0 ;Is it the end?
- JZ END_TEXT
- STOSB ;If no, store character.
- INC DI ;Bump past attribute.
- JMP SHORT NEXT_TEXT
- END_TEXT: LOOP STORE_TEXT
-
- MOV CX,12 ;Placement of 12 characters.
- STORE_BYTE: LODSW ;Get offset.
- MOV DI,AX
- ADD DI,BX ;Add window offset.
- MOVSB ;Store it.
- LOOP STORE_BYTE
-
- MOV DH,4 ;Placement of 4 columns of chars.
- STORE_MIDDLE: LODSW ;Get offset.
- MOV DI,AX
- ADD DI,BX ;Add window offset.
- LODSB ;Get character.
- MOV CX,10 ;Ten rows to place.
- NEXT_MIDDLE: STOSB ;Store it.
- ADD DI,89 ;Next row.
- LOOP NEXT_MIDDLE
- DEC DH
- JNZ STORE_MIDDLE
-
- ;---------------------------------------------------------;
- ; This routine places the foreground color in the window. ;
- ;---------------------------------------------------------;
-
- MOV AL,BYTE PTR FOREGROUND
- MOV DI,OFFSET WINDOW+1 ;Point to top row.
- MOV CX,45 ;45 attributes.
- TOP_ROW: STOSB ;Store it.
- INC DI ;Bump past character byte.
- LOOP TOP_ROW
-
- MOV BH,11 ;11 rows.
- MOV DI,OFFSET WINDOW+(90*2)+3 ;Point to middle of window.
- NEXT_ROW2: CALL STORE_LINE ;Store a line.
- ADD DI,4 ;Next row.
- DEC BH
- JNZ NEXT_ROW2
-
- MOV CX,2 ;2 rows.
- MOV DI,OFFSET WINDOW+(90*14)+5 ;Point to "F1".
- NEXT_FUNCT: STOSB ;Store two attributes.
- INC DI
- STOSB
- ADD DI,31 ;Point to "F2".
- STOSB ;Store two attributes.
- INC DI
- STOSB
- MOV DI,OFFSET WINDOW+(90*15)+5 ;Next row.
- LOOP NEXT_FUNCT
-
- CALL UPDATE_DAY ;Place date in window.
-
- ;----------------------------------------------------------------------;
- ; We need the current hour, screen buffer segment and status register. ;
- ;----------------------------------------------------------------------;
-
- CARD: MOV AX,40H ;Point to ROM BIOS data area
- MOV ES,AX
- MOV AX,ES:[6EH] ;Initialize current hour so alarm
- MOV LAST_HOUR,AX ; won't ring upon install.
- MOV AX,ES:[63H] ;Get base address of video card.
- ADD AX,6 ;Convert to status register
- MOV STATUS_REG,AX ; and store.
- CMP AX,3BAH ;Is it mono card?
- JZ INTERRUPT ;If yes, go to interrupt
- ADD SCREEN_SEG,800H ; else point to color card.
-
- ;----------------------------------------------------------------;
- ; Ready to install. We will take keyboard and timer interrupts. ;
- ;----------------------------------------------------------------;
-
- INTERRUPT: MOV AX,3509h ;Get keyboard interrupt.
- INT 21H
- MOV WORD PTR OLD_KEYBOARD,BX ;Save old interrupt.
- MOV WORD PTR OLD_KEYBOARD[2],ES
-
- MOV DX,OFFSET NEW_KEYBOARD ;Install new interrupt.
- MOV AX,2509h
- INT 21H
-
- MOV AX,351CH ;Get timer tick vector
- INT 21H
- MOV WORD PTR OLD_TIMER,BX ; and store offset
- MOV WORD PTR OLD_TIMER[2],ES ; and segment.
-
- MOV DX,OFFSET NEW_TIMER ;Replace with our
- MOV AX,251CH ; offset and segment.
- INT 21H
-
- MOV DX,OFFSET END_RESIDENT+1 ;Terminate but stay resident
- INT 27H
-
- ;------------------------------------------------------------------;
- ; This subroutine gets the current date and puts it in the window. ;
- ;------------------------------------------------------------------;
-
- UPDATE_DAY: MOV AH,2AH ;Get the date from DOS.
- INT 21H
- PUSH AX ;Save day of week.
- MOV AL,DH ;Retrieve month.
- XOR AH,AH
- MOV DI,OFFSET WINDOW+48 ;Point to storage.
- MOV BH,1 ;Suppress leading zero.
- CALL STORE_NUMBER ;Store it.
-
- MOV AL,DL ;Retrieve day.
- XOR AH,AH
- MOV BH,0 ;Store leading zero.
- CALL STORE_NUMBER
-
- MOV AX,CX ;Retrieve year.
- SUB AX,1900 ;Throw away the century half
- CMP AX,100 ; of year; if still over one
- JB NOT_2000 ; hundred, subtract 100 for turn
- SUB AX,100
- NOT_2000: CALL STORE_NUMBER ; of century. (planning far ahead)
-
- POP AX ;Retrieve day of week.
- MOV CL,3 ;Point to the appropriate
- MUL CL ; three character weekday
- MOV SI,OFFSET WEEKDAY ; and move into window.
- ADD SI,AX
- MOV CX,3
- NEXT_WEEKDAY: MOVSB
- INC DI ;Bump past attribute.
- LOOP NEXT_WEEKDAY
- RET
-
- ;----------------------------------------------;
- ; This subroutine stores a line of attributes. ;
- ;----------------------------------------------;
-
- STORE_LINE: MOV CX,43 ;43 attributes.
- NEXT_LINE1: STOSB
- INC DI ;Bump past character.
- LOOP NEXT_LINE1
- RET
-
- ;-----------------------------------------------------------;
- ; This subroutine converts a command line parameter to hex. ;
- ;-----------------------------------------------------------;
-
- GET_PARA: XOR BX,BX ;Start with zero.
- NEXT_DECIMAL: LODSB ;Get a character.
- CMP AL,',' ;Delimiter?
- JBE END_DECIMAL ;If yes, done.
- SUB AL,30H ;Convert to hex.
- XOR AH,AH
- MOV BP,AX ;Save it in BP.
- MOV AX,10
- XOR DX,DX ;Shift to left by multiplying
- MUL BX ; last pass by ten.
- MOV BX,AX ;Save in BX.
- ADD BX,BP ;Add new number.
- JMP SHORT NEXT_DECIMAL
-
- END_DECIMAL: MOV AX,BX ;Number in AX
- RET
-
- ;--------------------------------------------------;
- ; Compressed data and offsets for window structure ;
- ;--------------------------------------------------;
-
- TEXT DB 10,0,'Reminder',0,184,0,'Time',0,204,0,'Appointment',0
- DB 236,4,186,' F1 Delete Line F2 Hourly Alarm Enabled ',186,0
- DB 70, 5,186,' F3 Insert Line F4 Time Display Enabled ',186,0
- DB 52,0,'-',58,0,'-',78,0,':',88,0,'M',90,0,201,178,0,187
- DB 180,0,186,12,1,186,146,4,204
- DB 234,4,185,160,5,200,248,5,188,14,1,186,22,1,':',32,1,'M',102,1,186
-
- CODE ENDS
- END START